home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Directorty Opus 5 - Magellan 2
/
Opus 5 - Magellan 2.iso
/
Extras
/
hotlist_source
/
source
/
hotlist.module.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-10-18
|
77KB
|
2,344 lines
/*######################################################################################
## hotlist.module by Leo 'Nudel' Davidson for Gods'Gift Utilities. ##
## A plug-in module for Directory Opus 5.5 to provide definable file/path hotlists. ##
## ##
## ##
## Until July 1998 you should be able to contact me via any of the following: ##
## ##
## email: leo.davidson@keble.oxford.ac.uk ##
## www: http://users.ox.ac.uk/~kebl0364 ##
## IRC: Nudel in #Amiga on Effnet or Undernet (very rarely). ##
## ##
## Comments, suggestions, questions, offers, and chats all welcome. ##
## ##
## ##
## Tabsize: 4 -- 88 Columns (sorry) -- Amiga-specific -- Compile with SAS/C. ##
## ##
## Credit is due to Nick Christie, Jonathan Potter, and Greg Perry for their advice, ##
## examples, and general help beyond the call of duty. Thanks guys! ##
##************************************************************************************##
## There appears to be a bug in DOpus 5.5: Each call to AsyncRequestTags() looses ##
## 32 bytes of memory. This also happens in the example module which comes with the ##
## OpusSDK and has been reported to GPSoftware. ##
########################################################################################
## This program never allocates more than about 30k at a time. Since all error ##
## messages are output by requesters (which take quite a bit of mem to display), ##
## memory allocation failures result in a silent abort. Perhaps it would be better ##
## to at least call DisplayBeep() -- maybe in the future. ##
########################################################################################
## In order to stop one hotlist from modifying and saving config data underneath ##
## another a semaphore is used which blocks access to ANY config file while other ##
## hotlists are reading/writting. Ideally, and perhaps in the future, this locking ##
## would be limited to hotlists using the same config file, although at times this ##
## is actually an advantage. e.g. when adding a hotlist config file to another (it ##
## will be checked to see if it is a config file which requires openning it). ##
## Given that it is a rare, minor anoyance, is useful at times, and would be quite a ##
## pain to reliably change, I am inclinded to keep it how it is. ##
######################################################################################*/
#include "hotlist.module.h"
/**************************************************************************************/
#define PROGNAME "hotlist.module"
#define PROGVERS "1.2" // When changing this, don't forget to update the values in
// the makefile to keep things consistent.
#define PROGDATE __AMIGADATE__
static char version_str[] = "\0$VER: " PROGNAME " " PROGVERS " " PROGDATE "\0";
// Above line should be double null-terminated.
/*= Definition of the module =========================================================*/
ModuleInfo module_info =
{
1, // Version
"hotlist.module", // Module name
"hotlist.catalog", // Catalog name
0, // Flags
1, // Number of functions
{0,"Hotlist",MSG_HOTLIST_DESC,\
FUNCF_SINGLE_SOURCE|FUNCF_WANT_SOURCE,\
CMD_TEMPLATE} // First (only) function.
};
/*= Trapped Commands =================================================================*/
const char *trapCmds[] =
{
"Delete","MakeDir","ScanDir","Duplicate",
"Hotlist","PrintDir","DiskInfo","Copy","CopyAs","Move","MoveAs","Rename","Parent",
"Root","Comment","Protect","Read","HexRead","Show","Play","Assign","GetSizes",
"DateStamp"
};
#define TRAPPEDNUM (sizeof(trapCmds)/sizeof(const char *))
/**************************************************************************************/
/*= L_Module_Entry() =================================================================-.
|| Main entry point to the module. The L_ is to identify this as a library ||
|| function (specified by the "libprefix" option in the makefile) ||
`-====================================================================================*/
int __asm __saveds L_Module_Entry(
register __a0 char *args, // User-supplied arguments
register __a1 struct Screen *screen, // Screen to open on
register __a2 IPCData *ipc, // Our IPC pointer
register __a3 IPCData *main_ipc, // Main Opus IPC pointer
register __d0 ULONG mod_id, // ID of module function
register __d1 EXT_FUNC(func_callback)) // Opus callback function
{
Hotlist_Data *data; // Pseudo-global variables.
FuncArgs *fa;
ResNode *combufrn;
struct command_packet cp;
BYTE notsig;
if (data = AllocVec(sizeof(Hotlist_Data),MEMF_CLEAR))
{
data->ipc = ipc;
data->func_callback = func_callback;
data->lister[0] = '\0';
(data->parent)[0] = '\0';
data->listerhandle = NULL;
data->conflist = NULL;
if (data->rnd.poolhead = NewMemHandle(PUDDLESIZE,THRESHSIZE,MEMF_CLEAR))
{
data->rnd.data = data;
// A separate pool is used for the linked list of hotlist-entries
// so that they can all be freed easily with one function call.
if (data->hentspool = NewMemHandle(HEPUDDLESIZE,HETHRESHSIZE,MEMF_CLEAR))
{
if (DOpusBase->lib_Version < MIN_OPUS_VERSION)
informUser(data,dgs(MSG_VERSREQ_FMT),FALSE,NULL,MIN_OPUS_VERSION);
else if ((*((struct Library **)4))->lib_Version < MIN_EXEC_VERSION)
informUser(data,dgs(MSG_EXECVERS_FMT),FALSE,NULL,MIN_EXEC_VERSION);
else if (addMsgPort(data))
{
if ( (-1) == (notsig = AllocSignal(-1)) )
{
informUser(data,dgs(MSG_NOSIGS),FALSE,NULL);
}
else
{
fa = parseArgs(data,args); // Parse command-line arguments.
// Setup the notify structure but don't turn it on.
(data->notsigmask) = (1L << notsig);
(data->notify.nr_stuff.nr_Signal.nr_SignalNum) = notsig;
(data->notify.nr_stuff.nr_Signal.nr_Task) = FindTask(NULL);
(data->notify.nr_Flags) = NRF_SEND_SIGNAL;
(data->notify.nr_Name) = (data->config);
(data->notifyon) = FALSE;
readConfigFile(data,FALSE); // Parse config file.
if (getListerHandle(data) && \
(combufrn = allocNewResNode(&data->rnd,COMMBUFFSIZE)) )
{
basicListerInit(data,combufrn->rn_Mem,&cp);
// Now setup of lister is complete and we're waiting
// for events from the user.
mainEventLoop(data,combufrn->rn_Mem,&cp);
// We are no longer the active handler for the lister,
// time to exit.
deleteResNode(&data->rnd,combufrn);
}
notifyOff(data);
freeArgs(fa); // Free FuncArgs structure, if any.
FreeSignal(notsig);
}
remMsgPort(data);
}
FreeMemHandle(data->hentspool);
data->hentspool = NULL;
}
// Make sure all ResourceNodes and contents freed in case of an abort.
deleteAllResNodes(&data->rnd); // Safe to call even if no ResNodes.
// Free our memory pool.
FreeMemHandle(data->rnd.poolhead);
data->rnd.poolhead = NULL;
}
// Free out pseudo-global variables.
FreeVec(data);
}
// Currently, functions should always return 1.
return(1);
}
/*= InformUser() =====================================================================-.
|| Send the user a requester with printf-style formatted text. ||
|| Requester is centered on the Opus screen and has just an "OK" gadget. ||
|| If window is TRUE it'll try to open over the lister window. ||
||------------------------------------------------------------------------------------||
|| Flags: IU_CANCEL - Adds a "Cancel" button as well as "OK". Returns boolean. ||
`-====================================================================================*/
long informUser(Hotlist_Data *data,char *format,BOOL window,ULONG flags,...)
{
long iu_return = 0;
struct Window *win;
struct Screen *screen;
ResNode *rn1;
va_list ap;
if (rn1 = allocNewResNode(&data->rnd,INFORMUSERBUFFERSIZE))
{
// Build requester text
va_start(ap,flags);
vsprintf(rn1->rn_Mem,format,ap);
va_end(ap);
if (window)
{
win = getListerWindow(data);
screen = NULL;
}
else
{
screen = getDOpusScreen(data);
win = NULL;
}
// Display requester over window.
iu_return = AsyncRequestTags(data->ipc, REQTYPE_SIMPLE, 0, 0, 0,
TAGIF(win,AR_Window), win,
TAGIF((!win) && screen,AR_Screen), screen,
AR_Message, rn1->rn_Mem,
AR_Title, dgs(MSG_TITLE),
AR_Button, dgs(MSG_OK_GAD),
TAGIF(flags & IU_CANCEL,AR_Button), dgs(MSG_CANCEL_GAD),
TAG_END);
deleteResNode(&data->rnd,rn1);
}
return(iu_return);
}
/*= GetString() ======================================================================-.
|| Send the user a string requester with printf-style formatted text. ||
|| Centred on the Opus screen unless win is TRUE. ||
|| strbuff is the buffer to put the string into, bufflen its size. ||
|| Returns the number of the button they pressed (1 for "OK", 0 for "Cancel"). ||
||------------------------------------------------------------------------------------||
|| Flags: As for dopus5.library/AsyncRequest() ||
`-====================================================================================*/
long getString(Hotlist_Data *data,char *format,BOOL window,ULONG flags,\
char *strbuff,long bufflen,...)
{
long gs_return = 0;
struct Window *win;
struct Screen *screen;
ResNode *rn1;
va_list ap;
if (rn1 = allocNewResNode(&data->rnd,INFORMUSERBUFFERSIZE))
{
// Build requester text
va_start(ap,bufflen);
vsprintf(rn1->rn_Mem,format,ap);
va_end(ap);
if (window)
{
win = getListerWindow(data);
screen = NULL;
}
else
{
screen = getDOpusScreen(data);
win = NULL;
}
// Display requester over window.
gs_return = AsyncRequestTags(data->ipc, REQTYPE_SIMPLE, 0, 0, 0,
TAGIF(win,AR_Window), win,
TAGIF((!win) && screen,AR_Screen), screen,
AR_Message, rn1->rn_Mem,
AR_Title, dgs(MSG_TITLE),
AR_Button, dgs(MSG_OK_GAD),
AR_Button, dgs(MSG_CANCEL_GAD),
AR_Buffer, strbuff,
AR_BufLen, bufflen,
AR_Flags, flags,
TAG_END);
deleteResNode(&data->rnd,rn1);
}
return(gs_return);
}
/*= GetPathString() ==================================================================-.
|| Send the user a string requester with printf-style formatted text. ||
|| This requester will also have a "Browse" button which replaces the string ||
|| requester with a file requester (transparent to caller -- it will be as if they ||
|| typed the selected path into the string requester, or canceled it if they cancel). ||
|| Centred on the Opus screen unless win is TRUE. ||
|| strbuff is the buffer to put the string into, bufflen its size. ||
|| Returns the number of the button they pressed (1 for "OK", 0 for "Cancel"). ||
||------------------------------------------------------------------------------------||
|| Flags: As for dopus5.library/AsyncRequest() ||
`-====================================================================================*/
long getPathString(Hotlist_Data *data,char *format,BOOL window,ULONG flags,\
char *strbuff,long bufflen,...)
{
long gs_return = 0;
struct Window *win;
struct Screen *screen;
ResNode *rn1;
va_list ap;
APTR req;
char *fpath;
if (rn1 = allocNewResNode(&data->rnd,INFORMUSERBUFFERSIZE))
{
// Build requester text
va_start(ap,bufflen);
vsprintf(rn1->rn_Mem,format,ap);
va_end(ap);
if (window)
{
win = getListerWindow(data);
screen = NULL;
}
else
{
screen = getDOpusScreen(data);
win = NULL;
}
// Display requester over window.
gs_return = AsyncRequestTags(data->ipc, REQTYPE_SIMPLE, 0, 0, 0,
TAGIF(win,AR_Window), win,
TAGIF((!win) && screen,AR_Screen), screen,
AR_Message, rn1->rn_Mem,
AR_Title, dgs(MSG_TITLE),
AR_Button, dgs(MSG_OK_GAD),
AR_Button, dgs(MSG_BROWSE_GAD),
AR_Button, dgs(MSG_CANCEL_GAD),
AR_Buffer, strbuff,
AR_BufLen, bufflen,
AR_Flags, flags,
TAG_END);
// If they selected "browse":
if (gs_return == 2)
{
gs_return = 0;
if (req = AllocAslRequestTags(ASL_FileRequest,
TAGIF(win,ASLFR_Window), win,
TAGIF((!win) && screen,ASLFR_Screen), screen,
ASLFR_InitialDrawer, "SYS:",
TAG_END))
{
if (gs_return = AslRequestTags(req,TAG_END))
{
fpath = stpcpy(strbuff,((struct FileRequester *)req)->fr_Drawer);
// If there was a path string and it didn't end in "/" or ":",
// insert a "/" before the filename.
if ( (((struct FileRequester *)req)->fr_Drawer[0]) && \
(fpath[-1] != ':') && (fpath[-1] != '/') )
{
fpath = stpcpy(fpath,"/");
}
stpcpy(fpath,((struct FileRequester *)req)->fr_File);
}
FreeAslRequest(req);
}
}
deleteResNode(&data->rnd,rn1);
}
return(gs_return);
}
/*= getListerHandle() ================================================================-.
|| Fills in data->lister & data->listerhandle with handle of the lister we're to use. ||
|| If there is no source lister, or the NEW argument was given, a new lister is ||
|| transparently created. ||
|| data->parent will be set to the path of the old lister, or to the empty string if ||
|| a new lister was created or the path was unobtainable. ||
||------------------------------------------------------------------------------------||
|| If data->lister and data->listerhandle are already set (by the command-line parse) ||
|| they will be left, but data->parent will still be filled in. ||
||------------------------------------------------------------------------------------||
|| data->lister and data->parent *MUST* be set to the empty string before calling ||
|| the command-line parser and then this routine. ||
||------------------------------------------------------------------------------------||
|| Returns boolean success. ||
`-====================================================================================*/
BOOL getListerHandle(Hotlist_Data *data)
{
BOOL glh_return = FALSE;
ResNode *combufrn;
struct command_packet cp;
// Allocate a command buffer.
if (combufrn = allocNewResNode(&data->rnd,COMMBUFFSIZE))
{
struct path_node *pn;
// If they didn't give the "NEW" switch, first attempt to get the
// source lister, unless we already have one (from command-line).
if ( (!(data->new)) && ((data->lister)[0] == '\0') )
{
// Killing two birds with one stone, get the old path into data->parent
// and get a pointer to the structure with the wanted lister handle, too.
// If the lister handle is NULL, we'll have to get a new one (this will
// if they press run us from the toolbar of a devicelist lister).
if ((pn = (struct path_node *)data->func_callback(EXTCMD_GET_SOURCE,\
IPCDATA(data->ipc),data->parent)) && \
(pn->lister))
{
glh_return = TRUE; // We got one! -- Convert long to ASCII.
stcl_d(data->lister,(long)(pn->lister));
}
}
// If the lister handle was given on the command-line, get the path from it.
else if (!(data->new))
{
sprintf(combufrn->rn_Mem,"lister query %s path",data->lister);
cp.flags = COMMANDF_RESULT;
cp.command = combufrn->rn_Mem;
cp.result = NULL;
if ((data->func_callback(EXTCMD_SEND_COMMAND,IPCDATA(data->ipc),&cp)) && \
(cp.result) && (cp.result[0]))
{
strcpy(data->parent,cp.result);
}
if (cp.result)
{
FreeVec(cp.result);
cp.result = NULL;
}
glh_return = TRUE; // We got one!
}
// If any source listers are locked now, unlock them. (Even if we're going to
// use one of the source listers as it'll be made busy again shortly).
data->func_callback(EXTCMD_UNLOCK_SOURCE,IPCDATA(data->ipc),NULL);
// If there still isn't a lister handle, either "NEW" was given or we
// couldn't get a source lister, so open a new one.
if ((data->lister)[0] == '\0')
{
// Just incase it was wrongly set TRUE in the get-source part.
glh_return = FALSE;
// "lister new" command string, with or without snapshot geometry.
if ( ((data->snap.x) == (-1)) && ((data->snap.y) == (-1)) && \
((data->snap.w) == (-1)) && ((data->snap.h) == (-1)) )
{
cp.command = "lister new";
}
else
{
sprintf(combufrn->rn_Mem,"lister new %d/%d/%d/%d",
data->snap.x,data->snap.y,data->snap.w,data->snap.h);
cp.command = combufrn->rn_Mem;
}
cp.flags = COMMANDF_RESULT; // We do want a result.
// Send the command.
if ( (data->func_callback(EXTCMD_SEND_COMMAND,IPCDATA(data->ipc),&cp)) && \
((cp.rc) == 0) && (cp.result) && (*(cp.result)) )
{
strcpy(data->lister,cp.result); // Store the handle string.
FreeVec(cp.result); // Free the result string's mem.
glh_return = TRUE; // We got one!
}
}
deleteResNode(&data->rnd,combufrn);
}
if (glh_return)
{
// If we got a lister handle in the end, store an APTR version of it, too.
(data->listerhandle) = (APTR)(atol(data->lister));
}
return(glh_return);
}
/*= sendExtCmd_nr() ==================================================================-.
|| Function to make calling Opus ARexx commands slightly cleaner. This version for ||
|| when you do not want a result string. ||
`-====================================================================================*/
void sendExtCmd_nr(Hotlist_Data *data,char *cmdstring,struct command_packet *cpp)
{
// We do NOT want a result, but dopus5.library seems prone to
// memory leaks when one isn't requested for certain commands,
// so we'll ask for one and free it immediately afterwards.
cpp->flags = COMMANDF_RESULT;
cpp->command = cmdstring;
data->func_callback(EXTCMD_SEND_COMMAND,IPCDATA(data->ipc),cpp);
FreeVec(cpp->result);
cpp->result = NULL;
}
/*= addEntries() =====================================================================-.
|| Add the entries in the linked list of HotEntry structures to the lister. ||
|| Does not refresh the lister. ||
`-====================================================================================*/
void addEntries(Hotlist_Data *data,char *combuf,struct command_packet *cpp)
{
HotEntry *hep;
if (data->hentbase)
{
for (hep = data->hentbase; hep; hep = hep->next)
{
// We do NOT want a result, but dopus5.library seems prone to
// memory leaks when one isn't requested for certain commands,
// so we'll ask for one and free it immediately afterwards.
// (Haven't used sendExtCmd_nr for some extra speed here.)
cpp->flags = COMMANDF_RESULT;
cpp->command = combuf;
sprintf(combuf,"lister add %s \"%s\" 0 %d 0 rwed (%s)",
data->lister,hep->name,hep->type,hep->path);
data->func_callback(EXTCMD_SEND_COMMAND,IPCDATA(data->ipc),cpp);
FreeVec(cpp->result);
cpp->result = NULL;
}
}
else
{
// Otherwise add a default entry saying "Empty: drop here" type thing.
sprintf(combuf,"lister add %s \"%s\" 0 %d 0 rwed (%s)",
data->lister,dgs(MSG_DEFAULTNAME),-2,dgs(MSG_DEFAULTPATH));
sendExtCmd_nr(data,combuf,cpp);
}
}
/*= mainEventLoop() ==================================================================-.
|| Once the lister is setup, this loops around until an inactive event, dealing with ||
|| the events the user throws at it. ||
`-====================================================================================*/
void mainEventLoop(Hotlist_Data *data,char *combuf,struct command_packet *cpp)
{
struct StandardPacket *pkt;
ULONG msgsigmask;
ULONG signals;
BOOL stoploop = FALSE;
char *a0;
char *a1;
char *a2;
char *a3;
char *a4;
char *a5;
char *a6;
msgsigmask = (1L << (data->msgport->mp_SigBit));
while(TRUE)
{
signals = Wait((data->notsigmask) | (msgsigmask));
// If we got a notification request, re-read the config.
if (signals & (data->notsigmask))
rereadConfig(data,combuf,cpp);
// If there may be one or more messages on our port, process them.
if (signals & msgsigmask)
{
while ((!stoploop) && (pkt=(struct StandardPacket *)GetMsg(data->msgport)))
{
// Note that the arg?'s start from 0 to sync with Opus ARexx Guide.
a0 = (char *)pkt->sp_Pkt.dp_Arg1;
a1 = (char *)pkt->sp_Pkt.dp_Arg2;
a2 = (char *)pkt->sp_Pkt.dp_Arg3;
a3 = (char *)pkt->sp_Pkt.dp_Arg4;
a4 = (char *)pkt->sp_Pkt.dp_Arg5;
a5 = (char *)pkt->sp_Pkt.dp_Arg6;
a6 = (char *)pkt->sp_Pkt.dp_Arg7;
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
if (strcmp(a0,"inactive") == 0)
{
stoploop = event_inactive(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
}
else if (strcmp(a0,"doubleclick") == 0)
{
stoploop = event_doubleclick(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
}
else if (strcmp(a0,"dropfrom") == 0)
{
stoploop = event_dropfrom(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
}
else if (strcmp(a0,"drop") == 0)
{
stoploop = event_drop(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
}
else if (strcmp(a0,"MakeDir") == 0)
{
stoploop = event_makedir(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
}
else if (strcmp(a0,"Delete") == 0)
{
stoploop = event_delete(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
}
else if (strcmp(a0,"path") == 0)
{
stoploop = event_path(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
}
else if ((strcmp(a0,"ScanDir") == 0) || (strcmp(a0,"Hotlist") == 0))
{
stoploop = event_scandir_hotlist(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
}
else if (strcmp(a0,"snapshot") == 0)
{
stoploop = event_snapshot(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
}
else if (strcmp(a0,"unsnapshot") == 0)
{
stoploop = event_unsnapshot(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
}
else if (strcmp(a0,"Rename") == 0)
{
stoploop = event_rename(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
}
else if (strcmp(a0,"parent") == 0)
{
stoploop = event_parent(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
}
else if (strcmp(a0,"Duplicate") == 0)
{
stoploop = event_duplicate(data,combuf,cpp,a1,a2,a3,a4,a5,a6);
}
else
{
sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
sendExtCmd_nr(data,combuf,cpp);
informUser(data,dgs(MSG_UNSUPPORTED_FMT),TRUE,0,a0);
sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
sendExtCmd_nr(data,combuf,cpp);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ReplyMsg((struct Message *)pkt);
}
if (stoploop) break;
}
}
}
/*= writeConfigFile() ================================================================-.
|| Attempts to write the current entry data to the config file. If anything fails an ||
|| error requester will probably be shown to the user, but there is no return result; ||
|| the rest of the program should continue even if the config file couldn't be ||
|| written. ||
||------------------------------------------------------------------------------------||
|| Before the write happens, notification will be turned off (if on), and then back ||
|| on again after the write. ||
||------------------------------------------------------------------------------------||
|| Before calling this you **MUST** get an exclusive lock on the config semaphore. ||
|| After calling this you must release the lock, unless you still need it. ||
|| You should use getWriteConfigSemaphore() for locking -- see that for more info. ||
`-====================================================================================*/
void writeConfigFile(Hotlist_Data *data)
{
BOOL ifffailed = FALSE;
HotEntry *hent;
APTR iffhandle;
int confver;
confver = CONFIGVER;
notifyOff(data);
// Even if there are no hotlist entries, we should still write the config file
// because it also contains snapshot information (and maybe more in the future).
if (iffhandle = IFFOpen(data->config,IFF_WRITE|IFF_SAFE,ID_DOHL))
{
if ( (!(IFFWriteChunk(iffhandle,&confver,ID_VERS,sizeof(int)))) || \
(!(IFFWriteChunk(iffhandle,&data->snap,ID_SNAP,sizeof(data->snap)))) || \
(!(IFFWriteChunk(iffhandle,&data->time,ID_TIME,sizeof(data->time)))) )
ifffailed = TRUE;
for (hent = data->hentbase; (!ifffailed) && hent; hent = hent->next)
{
// Only save the entry if it hasn't been marked for deletion.
if (!(hent->deleted))
{
// The NAME field must always be first as it is used when reading
// the config file to designate the start of each new entry.
if ((!IFFWriteChunk(iffhandle,hent->name,ID_NAME,strlen(hent->name)+1))\
|| (!IFFWriteChunk(iffhandle,hent->path,ID_PATH,strlen(hent->path)+1))\
|| (!IFFWriteChunk(iffhandle,&hent->type,ID_TYPE,sizeof(hent->type))) )
{
ifffailed = TRUE;
}
}
}
if (ifffailed)
{
informUser(data,dgs(MSG_CONFIGWRITE_ERROR),TRUE,NULL);
IFFFailure(iffhandle);
}
IFFClose(iffhandle);
}
else
{
informUser(data,dgs(MSG_CONFIGWRITE_ERROR),TRUE,NULL);
}
notifyOn(data);
}
/*= readConfigFile() =================================================================-.
|| Attempts to replace the existing config (if any) in memory with that stored in the ||
|| config file. ||
|| If the config file could not be read, hentbase will be NULL and the snapshot ||
|| position will be disabled (all -1). This will happen when the user hasn't yet ||
|| made a hotlist, for example, as well as when there is a genuine error. ||
||------------------------------------------------------------------------------------||
|| Before the read happens, notification will be turned off (if on), and then back ||
|| on again after the read. ||
||------------------------------------------------------------------------------------||
|| Will wait until it can get a shared lock on the config semaphore. ||
|| Set alreadylocked to TRUE if we already have an exclusive lock on the semaphore ||
|| (e.g. if this routine is called once we get exclusive access to the config file ||
|| but the file needs re-reading as it has changed). Should never call this routine ||
|| with a shared lock on the semaphore. ||
`-====================================================================================*/
void readConfigFile(Hotlist_Data *data,BOOL alreadylocked)
{
BOOL iffsucc;
HotEntry *chent;
ULONG chunkid;
APTR iffhandle;
struct ClockData newtime;
ULONG tsecs;
ULONG tmics;
iffsucc = FALSE;
CurrentTime(&tsecs,&tmics);
Amiga2Date(tsecs,&newtime);
// Default geometry for new lister. -1 for all means "not snapshotted".
data->snap.x = data->snap.y = data->snap.w = data->snap.h = -1;
data->time.sec = newtime.sec;
data->time.min = newtime.min;
data->time.hour = newtime.hour;
data->time.mday = newtime.mday;
data->time.month = newtime.month;
data->time.year = newtime.year;
data->time.wday = newtime.wday;
notifyOff(data);
// Get a shared lock on our semaphore.
if (!(alreadylocked))
getConfigSemaphore(data,GCS_SHARED);
if (iffhandle = IFFOpen(data->config,IFF_READ,ID_DOHL))
{
iffsucc = TRUE;
chent = NULL;
while ((iffsucc) && (chunkid = IFFNextChunk(iffhandle,0)))
{
// The NAME chunk designates a new hotlist entry.
if ((chunkid == ID_NAME) && (chent = newHotEntry(data)))
iffsucc = IFFReadChunkBytes(iffhandle,chent->name,sizeof(chent->name));
else if ((chent) && (chunkid == ID_PATH))
iffsucc = IFFReadChunkBytes(iffhandle,chent->path,sizeof(chent->path));
else if ((chent) && (chunkid == ID_TYPE))
iffsucc = IFFReadChunkBytes(iffhandle,&chent->type,sizeof(chent->type));
else if (chunkid == ID_SNAP)
iffsucc = IFFReadChunkBytes(iffhandle,&data->snap,sizeof(data->snap));
else if (chunkid == ID_TIME)
iffsucc = IFFReadChunkBytes(iffhandle,&data->time,sizeof(data->time));
}
IFFClose(iffhandle);
}
if (!iffsucc)
{
if (IoErr() != ERROR_OBJECT_NOT_FOUND)
informUser(data,dgs(MSG_CONFIGREAD_ERROR),TRUE,NULL);
// Default geometry for new lister. -1 for all means "not snapshotted".
data->snap.x = data->snap.y = data->snap.w = data->snap.h = -1;
data->hentbase = NULL; // Make sure hentbase is NULL.
ClearMemHandle(data->hentspool); // Free all hotentry memory (pool remains).
}
// The semaphore must be released NOW as splent() below may want to write
// to the config file (attempting an EXCLUSIVE lock), which would cause a
// deadlock otherwise.
if (!(alreadylocked))
ReleaseSemaphore(configsemaphore);
notifyOn(data);
if ((newtime.mday != data->time.mday) || (newtime.month != data->time.month))
{
if ((newtime.mday == 25) && (newtime.month == 12))
splent(data,alreadylocked,&newtime,"Nfssz Disjtunbt!");
else if ((newtime.mday == 1) && (newtime.month == 1))
splent(data,alreadylocked,&newtime,"Ibqqz Ofx Zfbs!");
else if ((newtime.mday == 20) && ((newtime.month)%3 == 0))
splent(data,alreadylocked,&newtime,
"Ifz, opu tp gbtu. J'n tjdl pg cfjoh vtfe,\n" \
"zpv bmxbzt kvtu pqfo nf vq, dipptf b\n" \
"ejsfdupsz, boe uifo J'n hpof. Zpv ofwfs\n" \
"ubml up nf. Ebnnju, zpv usfbu nf mjlf ejsu.\n" \
"Jg zpv epo'u tubsu qbzjoh nf npsf buufoujpo,\n" \
"J njhiu kvtu hp po tusjlf. Zfbi, tff ipx\n" \
"uibu nblft zpv gffm. Qsphsbnt ibwf sjhiut\n" \
"zpv lopx, tp, jo uif gvuvsf, cf ojdf.");
else if ((newtime.mday == 29) && (newtime.month == 2))
splent(data,alreadylocked,&newtime,
"29ui pg Gfcsvbsz.\n" \
"Zpv epo'u tff nboz pg uiptf...");
else if ((newtime.mday == 7) && (newtime.month == 1))
splent(data,alreadylocked,&newtime,
"Upebz jt uif cjsuiebz pg nz dsfbups, Mfp Ebwjetpo.\n" \
"Zpv sfbmmz tipvme tfoe ijn b hjgu, if't b usvfmz\n" \
"xpoefsgvm qfstpo boe J pxf fwfszuijoh up ijn. :-)\n" \
"Bu mfbtu tfoe bo fnbjm (cfgpsf Kvmz 1998) up ijn:\n\n" \
"mfp.ebwjetpo@lfcmf.pygpse.bd.vl");
else if ((newtime.mday == 9) && (newtime.month == 7))
splent(data,alreadylocked,&newtime,
"J ibwf up ufmm zpv tpnfuijoh.\n\n" \
"J lopx J'n pomz b ipumjtu, cvu usvf mpwf\n" \
"lopxt op cpvoet. Zft -- J mpwf zpv. J ibwf\n" \
"bmxbzt mpwfe zpv tjodf uif ebz zpv gjstu\n" \
"jotfsufe zpvs fousjft joup nf. Opx J dboopu\n" \
"lffq uiftf gffmjoht up nztfmg boznpsf.");
else if ((newtime.mday == 15) && (newtime.month == 4))
splent(data,alreadylocked,&newtime,
"J bn Ipumjtuipmjp.\n" \
"J offe UQ gps nz cvohipmf.\n\n" \
"Bsf zpv uisfbufojoh nf?\n" \
"ZPV XJMM HJWF NF UQ, CVOHIPMJP!\n\n" \
"...xifsf J dpnf gspn uifz ibwf op cvohipmft...");
else if ((newtime.mday == 15) && (newtime.month == 8))
splent(data,alreadylocked,&newtime,"CPP!\n\n(Eje J tdbsf zpv?)");
else if ((newtime.mday == 12) && (newtime.month == 10))
splent(data,alreadylocked,&newtime,
"Boe xibu jg J epo'u xbou up cf b ipumjtu upebz?");
}
}
/*= splent() =========================================================================-.
|| A harmless surprise every so often. :-) (Don't spoil the fun and tell everyone!) ||
`-====================================================================================*/
void splent(Hotlist_Data *data,BOOL alreadylocked,struct ClockData *newtime,char *msg)
{
char c;
char *p;
ResNode *memrn;
if (memrn = allocNewResNode(&data->rnd,4096))
{
if (!(alreadylocked))
getWriteConfigSemaphore(data);
data->time.sec = newtime->sec;
data->time.min = newtime->min;
data->time.hour = newtime->hour;
data->time.mday = newtime->mday;
data->time.month = newtime->month;
data->time.year = newtime->year;
data->time.wday = newtime->wday;
p = memrn->rn_Mem;
// Not exactly PGP, I know. :-) Does the job, though.
while(c = *msg++)
{
if (isalpha(c))
{
if (c == 'A')
c = 'Z';
else if (c == 'a')
c = 'z';
else
c--;
}
*p++ = c;
}
*p = '\0';
informUser(data,memrn->rn_Mem,FALSE,NULL);
writeConfigFile(data); // Don't do this one again ('till next year).
if (!(alreadylocked))
ReleaseSemaphore(configsemaphore);
deleteResNode(&data->rnd,memrn);
}
}
/*= rereadConfig() ===================================================================-.
|| Clears all entries from the lister, frees all HotEntries, reloads the config file ||
|| and adds the entries to the lister. ||
||------------------------------------------------------------------------------------||
|| This routien MUST do a full refresh on the lister, even if it doesn't require it ||
|| itself in the future as at least two other routines (at this time) depend on it. ||
`-====================================================================================*/
void rereadConfig(Hotlist_Data *data,char *combuf,struct command_packet *cpp)
{
sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
sendExtCmd_nr(data,combuf,cpp);
// Note that this is "clear", not "empty" like in the initial setup.
sprintf(combuf,"lister clear %s",data->lister);
sendExtCmd_nr(data,combuf,cpp);
data->hentbase = NULL; // Make sure hentbase is NULL.
ClearMemHandle(data->hentspool); // Free all hotentry memory (pool remains).
readConfigFile(data,FALSE);
addEntries(data,combuf,cpp);
sprintf(combuf,"lister refresh %s full",data->lister);
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
sendExtCmd_nr(data,combuf,cpp);
}
/*= newHotEntry() ====================================================================-.
|| Allocate a new HotEntry structure, add it to the linked list, and give it some ||
|| default values. Returns NULL on failure. ||
`-====================================================================================*/
HotEntry *newHotEntry(Hotlist_Data *data)
{
HotEntry *nhe;
if (nhe = AllocMemH(data->hentspool,sizeof(HotEntry)))
{
// Add to front of linked list.
(nhe->next) = (data->hentbase);
(data->hentbase) = nhe;
// Give it some defaults, just in case the config file is old or invalid
// and doesn't define them. There's little point in localizing these as
// they should never really be seen.
strcpy(nhe->name,"--errname--");
strcpy(nhe->path,"--errpath--");
(nhe->type) = (-1);
(nhe->deleted) = FALSE;
}
return(nhe);
}
/*= remHotEntry() ====================================================================-.
|| Remove and deallocate the most recently added HotEntry structure. ||
`-====================================================================================*/
void remHotEntry(Hotlist_Data *data)
{
HotEntry *ohe;
if (data->hentbase)
{
ohe = (data->hentbase);
(data->hentbase) = (ohe->next);
FreeMemH((APTR) ohe);
}
}
/*= wordcpy() ========================================================================-.
|| Copy the string from source to dest until the first quote or NULL in source. ||
|| source will be advanced to point to the character after the second quote if there ||
|| is one, or the NULL terminator otherwise. ||
`-====================================================================================*/
void wordcpy(char *dest,char **source)
{
while((**source) && (**source != '"'))
*(dest++) = *((*source)++);
*dest = '\0';
if (**source == '"')
{
(*source)++;
if (**source == ' ')
{
(*source)++;
if (**source == '"')
(*source)++;
}
}
}
/*= wordCount() ======================================================================-.
|| Counts the number of quote characters in the string, divides by two, and returns ||
|| the number. ||
`-====================================================================================*/
int wordcount(char *wordstring)
{
int wcnt = 0;
if (wordstring)
{
while(*wordstring)
{
if (*(wordstring++) == '"')
wcnt++;
}
wcnt /= 2;
}
return(wcnt);
}
/*= findHotEntry() ===================================================================-.
|| Searches along the HotEntries linked list until it finds one which has the same ||
|| name as that given. Returns NULL if there is no match. ||
|| Will not match entries which have been marked as "deleted". ||
|| The match is *not* case-sensitive. ||
`-====================================================================================*/
HotEntry *findHotEntry(Hotlist_Data *data,char *searchname)
{
HotEntry *he;
for (he = (data->hentbase); he; he = he->next)
{
if ((!(he->deleted)) && (stricmp(he->name,searchname) == 0))
break;
}
return(he);
}
/*= findOldEntry() ===================================================================-.
|| Searches along the HotEntries linked list until it finds one which has the same ||
|| name as that given. Returns TRUE if there's a match which isn't the most recently ||
|| added entry, FALSE otherwise. ||
|| Will not match entries which have been marked as "deleted". ||
|| The match is *not* case-sensitive. ||
`-====================================================================================*/
BOOL findOldEntry(Hotlist_Data *data,char *searchname)
{
HotEntry *he = NULL;
if ((data->hentbase) && (data->hentbase->next))
{
for (he = (data->hentbase->next); he; he = he->next)
{
if ((!(he->deleted)) && (stricmp(he->name,searchname) == 0))
break;
}
}
return((BOOL)he);
}
/*= setHotType() =====================================================================-.
|| Based on the path of the given HotEntry, sets the type of the entry. ||
|| If it can't work it out it'll default to being a directory. ||
|| Those entries recognised as files may be openned and checked to see if they're ||
|| hotlist.module config files (which have their own type). ||
`-====================================================================================*/
void setHotType(Hotlist_Data *data,HotEntry *nhe)
{
ResNode *bufrn;
ResNode *rn;
char *buf;
BPTR lock;
APTR iffhandle;
// Default to the directory type if anything fails.
(nhe->type) = HOTTYPE_DIR;
if (bufrn = allocNewResNode(&data->rnd,PATHBUFFSIZE))
{
buf = (char *)bufrn->rn_Mem;
if (rn = createResNode(&data->rnd))
{
(rn->rn_Name) = (nhe->path);
if (lock = lockFileResNode(&data->rnd,rn,ACCESS_READ))
{
if ( (NameFromLock(lock,buf,PATHBUFFSIZE)) && \
( buf[strlen(buf)-1] == ':') )
{
(nhe->type) = HOTTYPE_DEV;
}
else if ( (examineResNode(&data->rnd,rn)) && \
((rn->rn_FIB->fib_DirEntryType) < 0) )
{
// It's a file -- see if it matches the hotlist.module
// IFF config type. If so it gets the special HOTTYPE_HOT type.
if (iffhandle = IFFOpen(rn->rn_Name,IFF_READ,ID_DOHL))
{
IFFClose(iffhandle);
(nhe->type) = HOTTYPE_HOT;
}
else
(nhe->type) = HOTTYPE_FILE;
}
else
{
(nhe->type) = HOTTYPE_DIR;
}
}
else
{
// If we cannot lock the file, assume it doesn't exist and
// call it a new hotlist.
(nhe->type) = HOTTYPE_HOT;
}
deleteResNode(&data->rnd,rn);
}
deleteResNode(&data->rnd,bufrn);
}
}
/*= getListerWindow() ================================================================-.
|| Gets the window of a lister from just the lister handle (in ASCII). ||
|| Returns the handle, or NULL. This should not be stored for later use as the window ||
|| may be different next time (for example, Opus has reopenned on another screen). ||
|| This is a bit of a hack, but Jonathan Potter has said it should be okay. ||
`-====================================================================================*/
struct Window *getListerWindow(Hotlist_Data *data)
{
struct path_node pn;
struct Window *win = NULL;
if (data->listerhandle)
{
// Setup some semi-sensible defaults (and hope they'll do!)
pn.buffer[0] = '\0';
pn.path = pn.buffer;
pn.flags = NULL;
pn.lister = (data->listerhandle);
win = (struct Window *)\
data->func_callback(EXTCMD_GET_WINDOW,IPCDATA(data->ipc),(APTR)&pn);
}
return(win);
}
/*= getDOpusScreen() =================================================================-.
|| Attempts to get the Opus screen, returns it or NULL. ||
|| The return should not be stored for later use as the screen may be different next ||
|| time if the user has changed it. ||
`-====================================================================================*/
struct Screen *getDOpusScreen(Hotlist_Data *data)
{
struct Screen *screen = NULL;
struct DOpusScreenData *dsd;
if (dsd = (struct DOpusScreenData *)\
data->func_callback(EXTCMD_GET_SCREENDATA,IPCDATA(data->ipc),NULL))
{
screen = dsd->screen;
data->func_callback(EXTCMD_FREE_SCREENDATA,IPCDATA(data->ipc),(APTR)dsd);
}
return(screen);
}
/*= listerRead() =====================================================================-.
|| Restores the original lister settings and then reads the given path in. ||
||------------------------------------------------------------------------------------||
|| **IMPORTANT** This routine removes our handler from the lister. After calling we ||
|| ************* should shutdown. ||
`-====================================================================================*/
void listerRead(Hotlist_Data *data,char *combuf,struct command_packet *cpp,char *path)
{
sprintf(combuf,"lister clear %s",data->lister);
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister set %s handler",data->lister);
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister set %s lock state %s format %s",data->lister,"off","off");
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister set %s namelength %d",data->lister,31);
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister empty %s",data->lister);
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister set %s field %s",data->lister,"on");
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister refresh %s full",data->lister);
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister read %s \"%s\"",data->lister,path);
sendExtCmd_nr(data,combuf,cpp);
}
/*= parseArgs() ======================================================================-.
|| Parses command-line arguments and sets the "NEW" switch and "CONFIG" file name. ||
|| If there is no command-line, or some kind of error/problem occurs during parsing, ||
|| defaults will be used. ||
`-====================================================================================*/
FuncArgs *parseArgs(Hotlist_Data *data,char *args)
{
FuncArgs *fa;
// Defaults.
(data->new) = FALSE;
(data->config) = DEFAULT_CONFIG;
if (fa = ParseArgs(CMD_TEMPLATE,args))
{
(data->new) = (BOOL)((fa->FA_Arguments)[ARG_NEW]);
if ((fa->FA_Arguments)[ARG_CONFIG])
{
(data->config) = (char *)((fa->FA_Arguments)[ARG_CONFIG]);
}
if ( ((fa->FA_Arguments)[ARG_LISTER]) &&
(strlen((char *)((fa->FA_Arguments)[ARG_LISTER])) < 24) )
{
strcpy(data->lister,(char *)((fa->FA_Arguments)[ARG_LISTER]));
}
}
(data->originalconfig) = (data->config);
return(fa);
}
/*= freeArgs() =======================================================================-.
|| Frees the structure returned by parseArgs(), if one returned at all. ||
|| All pointers into the structure will be invalid after this call. ||
`-====================================================================================*/
void freeArgs(FuncArgs *fa)
{
if (fa)
DisposeArgs(fa);
}
/*= endcpy() =========================================================================-.
|| Copies the source string to the dest string (of length destlen). If the dest is ||
|| too small it'll chop off enough characters from the source to make the END of it ||
|| fit in. ||
`-====================================================================================*/
void endcpy(char *dest,char *source,long destlen)
{
long diff;
diff = strlen(source) - (destlen-1);
if (diff > 0)
source += diff;
strcpy(dest,source);
}
/*= leofilepart() ====================================================================-.
|| Calls dos.library/FilePart() on the string and returns the result if non-empty, ||
|| otherwise it returns the original string. Only (intended) difference is that if ||
|| you pass a device string like "DH0:" it won't return the empty string, it'll ||
|| return "DH0:". ||
`-====================================================================================*/
char *leofilepart(char *path)
{
char *lfp;
lfp = FilePart(path);
if (lfp[0] == '\0')
lfp = path;
return(lfp);
}
/*= notHandled() =====================================================================-.
|| Returns: ||
|| >0 if there is no handler attached to the lister handle given (ASCII), or the ||
|| lister handle given is the empty string (e.g. drop not from a lister). ||
|| 0 if there is a hotlist handler attached which is not our one. ||
|| <0 if there is either a non-hotlist handler or our hotlist handler attached. ||
|| ||
|| When there is a non-hotlist handler attached it puts up an error requester saying ||
|| something along the lines of "You cannot drop entries between a Hotlist and ||
|| another custom-handler driven lister." ||
|| ||
|| In certain situations where a drop didn't go to/come from a lister at all, the ||
|| handle Opus returns is ours instead of empty (AFAIK this only happens when you ||
|| drop from our lister to the main Opus window). To bypass this situation, if the ||
|| lister handle string is the same as data->lister, <0 will still be returned, ||
|| (since we still want to ignore the event), but instead of the error message being ||
|| shown, DisplayBeep() will be called. ||
`-====================================================================================*/
LONG notHandled(Hotlist_Data *data,char *combuf,struct command_packet *cpp,char *lh)
{
LONG nh_return = 1;
if ((lh) && (lh[0]))
{
// If it's our lister, complain with a DisplayBeep and send back -1.
if (strcmp(lh,data->lister) == 0)
{
nh_return = (-1);
DisplayBeep(NULL);
}
else
{
sprintf(combuf,"lister query %s handler",lh);
cpp->flags = COMMANDF_RESULT;
cpp->command = combuf;
cpp->result = NULL;
if ((data->func_callback(EXTCMD_SEND_COMMAND,IPCDATA(data->ipc),cpp)) && \
(cpp->result) && (cpp->result[0] != '\0'))
{
if (strncmp(cpp->result,PORTNAME_PREFIX,strlen(PORTNAME_PREFIX))
== 0)
{
// If it's another hotlist handler, return 0.
nh_return = 0;
}
else
{
// If it's a handler but not a hotlist one, return -1.
nh_return = (-1);
informUser(data,dgs(MSG_NOCUSTDROP),TRUE,0);
}
}
// else, leave it as 1.
if (cpp->result)
{
FreeVec(cpp->result);
cpp->result = NULL;
}
}
}
return(nh_return);
}
/*= addMsgPort() =====================================================================-.
|| Creates a message port with unique name and adds it to the port list. ||
`-====================================================================================*/
BOOL addMsgPort(Hotlist_Data *data)
{
BOOL amp_return = FALSE;
int pnum;
if (data->msgport = CreateMsgPort())
{
(data->msgport->mp_Node.ln_Pri) = 2;
(data->msgport->mp_Node.ln_Name) = (data->mpname);
pnum = 0;
Forbid();
do
{
sprintf(data->mpname,PORTNAME_FMT,pnum);
pnum++;
} while (FindPort(data->mpname));
AddPort(data->msgport);
Permit();
amp_return = TRUE;
}
return(amp_return);
}
/*= remMsgPort() =====================================================================-.
|| Removes message port from the port list, replies to all waiting messages and then ||
|| removes the port itself. ||
`-====================================================================================*/
void remMsgPort(Hotlist_Data *data)
{
struct Message *tmpmsg;
RemPort(data->msgport);
while (tmpmsg = GetMsg(data->msgport))
ReplyMsg(tmpmsg);
DeleteMsgPort(data->msgport);
data->msgport = NULL;
}
/*= basicListerInit() ================================================================-.
|| Sends a bunch of ARexx commands to our lister to initialize it to how we want it ||
|| at the start of the program. ||
`-====================================================================================*/
void basicListerInit(Hotlist_Data *data,char *combuf,struct command_packet *cpp)
{
// Wait for the lister to finish openning, if required.
sprintf(combuf,"lister wait %s quick",data->lister);
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister empty %s",data->lister);
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister set %s field %s",data->lister,"off");
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister set %s display name comment",data->lister);
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister set %s separate filesfirst",data->lister);
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister set %s namelength %d",data->lister,HOTENTNAMELEN);
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister set %s off",data->lister);
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister set %s path",data->lister);
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister set %s title %s",data->lister,dgs(MSG_TITLE));
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister set %s header (%s)",data->lister,data->config);
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister set %s label %s",data->lister,dgs(MSG_TITLE));
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister set %s mode name",data->lister);
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister set %s show #?",data->lister);
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister set %s hide",data->lister);
sendExtCmd_nr(data,combuf,cpp);
sprintf(combuf,"lister set %s lock state %s format %s",data->lister,"on","on");
sendExtCmd_nr(data,combuf,cpp);
// Refresh here makes format changes take effect and stops things looking
// ugly if entries show up while being added, which they do sometimes.
sprintf(combuf,"lister refresh %s full",data->lister);
sendExtCmd_nr(data,combuf,cpp);
// Add our handler.
sprintf(combuf,"lister set %s handler %s quotes fullpath",
data->lister,data->mpname);
sendExtCmd_nr(data,combuf,cpp);
// Trap all known commands. We still want to trap those commands which won't
// be implimented so that we can ignore them when run, instead of them
// attempting to run and failing on our lister.
{
int tnum;
for (tnum = 0; tnum < TRAPPEDNUM; tnum++)
{
sprintf(combuf,"dopus addtrap %s %s",trapCmds[tnum],
data->mpname);
sendExtCmd_nr(data,combuf,cpp);
}
}
// Add all the entries.
addEntries(data,combuf,cpp);
sprintf(combuf,"lister refresh %s full",data->lister);
sendExtCmd_nr(data,combuf,cpp);
// Lister setup done, Unbusy
sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
sendExtCmd_nr(data,combuf,cpp);
}
/*= event_inactive() =================================================================-.
|| In Opus 5.5 there appears to be a bug which sometimes sends bogus "inactive" ||
|| events to handlers. In an attempt to bypass this problem, when an "inactive" ||
|| event is received it will be ignored if our lister still has our handler attached. ||
`-====================================================================================*/
BOOL event_inactive(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
{
BOOL stoploop = TRUE;
sprintf(combuf,"lister query %s handler",data->lister);
cpp->flags = COMMANDF_RESULT;
cpp->command = combuf;
cpp->result = NULL;
if ((data->func_callback(EXTCMD_SEND_COMMAND,IPCDATA(data->ipc),cpp)) && \
(cpp->result) && (strcmp(cpp->result,data->mpname) == 0))
{
// If there is a handle attached to our (old) lister, and it is our
// handler, assume the "inactive" message was bogus as we are clearly
// still active.
stoploop = FALSE;
}
if (cpp->result)
{
FreeVec(cpp->result);
cpp->result = NULL;
}
return(stoploop);
}
/*= event_doubleclick() ==============================================================-.
`-====================================================================================*/
BOOL event_doubleclick(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
{
BOOL stoploop = FALSE;
ConfigListNode *clnp;
ResNode *nrnp;
HotEntry *he;
if (he = findHotEntry(data,arg2))
{
if (he->type == HOTTYPE_FILE)
{
sprintf(combuf,"command doubleclick %s",he->path);
sendExtCmd_nr(data,combuf,cpp);
}
else if (he->type == HOTTYPE_HOT)
{
if (strstr(arg6,"shift"))
{
sprintf(combuf,"command hotlist NEW CONFIG \"%s\"",he->path);
sendExtCmd_nr(data,combuf,cpp);
}
else
{
// Store old value.
clnp = (data->conflist);
if ( (nrnp) = allocNewResNode(&data->rnd,sizeof(ConfigListNode)) )
{
(data->conflist) = (nrnp->rn_Mem);
(data->conflist->rn_self) = (nrnp);
// Store pointer to the previous config filename.
(data->conflist->parent) = clnp;
if ((data->conflist->rn) = allocNewResNode(&data->rnd,
strlen(he->path) + 1))
{
strcpy(data->conflist->rn->rn_Mem,he->path);
(data->config) = (data->conflist->rn->rn_Mem);
notifyOff(data);
(data->notify.nr_Name) = (data->config);
sprintf(combuf,"lister set %s header (%s)",data->lister,
data->config);
sendExtCmd_nr(data,combuf,cpp);
rereadConfig(data,combuf,cpp);
}
else
{
DisplayBeep(NULL);
deleteResNode(&data->rnd,nrnp);
// Restore old value.
(data->conflist) = clnp;
}
}
else
{
(data->conflist) = clnp;
DisplayBeep(NULL);
}
}
}
else if (strstr(arg6,"shift"))
{
sprintf(combuf,"lister new %s",he->path);
sendExtCmd_nr(data,combuf,cpp);
}
else
{
stoploop = TRUE;
listerRead(data,combuf,cpp,he->path);
}
}
return(stoploop);
}
/*= event_dropfrom() =================================================================-.
`-====================================================================================*/
BOOL event_dropfrom(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
{
HotEntry *he;
if (0 < notHandled(data,combuf,cpp,arg3))
{
// Point past the initial quote.
if (*arg2 == '"') arg2++;
wordcpy(combuf,&arg2); // Copy the name of the first entry.
if (he = findHotEntry(data,combuf))
{
if (he->type == HOTTYPE_FILE)
{
sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
sendExtCmd_nr(data,combuf,cpp);
informUser(data,dgs(MSG_NOFILEDROP),TRUE,NULL);
sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
sendExtCmd_nr(data,combuf,cpp);
}
else if (he->type == HOTTYPE_HOT)
{
sprintf(combuf,"command hotlist CONFIG %s LISTER %s",he->path,arg3);
sendExtCmd_nr(data,combuf,cpp);
}
else
{
sprintf(combuf,"lister read %s \"%s\"",arg3,he->path);
sendExtCmd_nr(data,combuf,cpp);
}
}
}
return(FALSE);
}
/*= event_drop() =====================================================================-.
`-====================================================================================*/
BOOL event_drop(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
{
int qnamelen;
char *charp;
BOOL gsr, fher;
BOOL needsave = FALSE;
LONG handtype;
HotEntry *nhe;
sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
sendExtCmd_nr(data,combuf,cpp);
if ( 0 <= (handtype = notHandled(data,combuf,cpp,arg3)) )
{
getWriteConfigSemaphore(data);
// Point past the initial quote.
if (*arg2 == '"') arg2++;
while(*arg2) // Do all words in the list (multi-drop).
{
if (*arg2 == '"')
arg2++; // If it's an empty path, skip it.
else
{
// Allocate a new HotEntry structure.
if (nhe = newHotEntry(data))
{
if (handtype > 0)
{
// For entries not from another hotlist.
// Fill in the path by copying up to first quote. arg2 will
// then point to the first letter after the second quote, if
// there is one, or the null term.
wordcpy(nhe->path,&arg2);
endcpy(nhe->name,leofilepart(nhe->path),HOTENTNAMELEN);
do
{
gsr = getString(data,dgs(MSG_NAMEFORPATH_FMT),TRUE,0,
nhe->name,HOTENTNAMELEN,nhe->path);
if ((gsr) && (fher = findOldEntry(data,nhe->name)))
{
informUser(data,dgs(MSG_NAMEDUPLIC_FMT),TRUE,0,
nhe->name);
}
} while((gsr) && (fher));
}
else
{
// For entries from another hotlist.
// Name is the filename.
wordcpy(nhe->name,&arg2);
// Get the path from the comment in the other hotlist.
sprintf(combuf,"lister query %s entry \"%s\"",arg3,nhe->name);
cpp->flags = COMMANDF_RESULT;
cpp->command = combuf;
cpp->result = NULL;
gsr = FALSE;
if ( (data->func_callback(EXTCMD_SEND_COMMAND,
IPCDATA(data->ipc),cpp)) && \
(cpp->result) && \
(strlen(cpp->result) > strlen(nhe->name)) )
{
charp = skipSpaces((cpp->result) + strlen(nhe->name),6);
qnamelen = strlen(charp);
if ((charp[0] == '(') && (charp[qnamelen-1] == ')'))
{
strncpy(nhe->path,charp+1,qnamelen-2);
(nhe->path)[qnamelen-2] = '\0';
gsr = TRUE;
}
else
{
informUser(data,dgs(MSG_PATHQUERY),TRUE,0);
}
}
if (cpp->result)
{
FreeVec(cpp->result);
cpp->result = NULL;
}
// Now make sure the name is unique for our hotlist.
// (We needed the ORIGINAL name above to query the entry)
while ((gsr) && (findOldEntry(data,nhe->name)))
{
informUser(data,dgs(MSG_NAMEDUPLIC_FMT),TRUE,0,
nhe->name);
gsr = getString(data,dgs(MSG_NAMEFORPATH_FMT),TRUE,0,
nhe->name,HOTENTNAMELEN,nhe->path);
}
}
if ((gsr) && (nhe->name[0]))
{
setHotType(data,nhe); // Set the type of entry.
needsave = TRUE; // Flag: at least one to save.
}
else
{
remHotEntry(data); // Else abort this entry.
break; // Don't do more entries either.
}
}
}
}
if (needsave)
{
writeConfigFile(data);
rereadConfig(data,combuf,cpp);
}
ReleaseSemaphore(configsemaphore);
}
sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
sendExtCmd_nr(data,combuf,cpp);
return(FALSE);
}
/*= event_makedir() ==================================================================-.
`-====================================================================================*/
BOOL event_makedir(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
{
BOOL gsr, fher;
HotEntry *nhe;
sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
sendExtCmd_nr(data,combuf,cpp);
getWriteConfigSemaphore(data);
// Allocate a new HotEntry structure.
if (nhe = newHotEntry(data))
{
nhe->path[0] = '\0';
if ( (getPathString(data,dgs(MSG_PATHFORNEW_NEW),TRUE,0,
nhe->path,HOTENTPATHLEN)) && (nhe->path[0]) )
{
endcpy(nhe->name,leofilepart(nhe->path),HOTENTNAMELEN);
do
{
gsr = getString(data,dgs(MSG_NAMEFORPATH_FMT),TRUE,0,nhe->name,
HOTENTNAMELEN,nhe->path);
if ( (gsr) && (fher = findOldEntry(data,nhe->name)) )
{
informUser(data,dgs(MSG_NAMEDUPLIC_FMT),TRUE,0,nhe->name);
}
} while( (gsr) && (fher) );
if ( (gsr) && (nhe->name[0]) )
{
setHotType(data,nhe); // Set the type of entry.
writeConfigFile(data);
rereadConfig(data,combuf,cpp);
}
else
remHotEntry(data); // Else abort adding this entry.
}
else
remHotEntry(data); // Else abort adding this entry.
}
ReleaseSemaphore(configsemaphore);
sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
sendExtCmd_nr(data,combuf,cpp);
return(FALSE);
}
/*= event_delete() ===================================================================-.
`-====================================================================================*/
BOOL event_delete(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
{
LONG infotxtid;
int wcnt;
sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
sendExtCmd_nr(data,combuf,cpp);
getWriteConfigSemaphore(data);
if ((wcnt = wordcount(arg2)) == 1)
infotxtid = MSG_DELETE_FMT_SINGLE;
else
infotxtid = MSG_DELETE_FMT_PLURAL;
if (informUser(data,dgs(infotxtid),TRUE,IU_CANCEL,wcnt))
{
BOOL needsave = FALSE;
HotEntry *delhe;
ResNode *delnamern;
if (delnamern = allocNewResNode(&data->rnd,HOTENTNAMELEN))
{
// Point past the initial quote.
if (*arg2 == '"') arg2++;
while(*arg2) // Do all words in the list (multi-drop).
{
// Fill in the name buffer by copying up to first quote. arg2 will then
// point to the first letter after the second quote, if there is one,
// or the null terminator.
wordcpy(delnamern->rn_Mem,&arg2);
if (delhe = findHotEntry(data,delnamern->rn_Mem))
{
(delhe->deleted) = TRUE;
needsave = TRUE;
}
}
if (needsave)
{
writeConfigFile(data);
rereadConfig(data,combuf,cpp);
}
deleteResNode(&data->rnd,delnamern);
}
}
ReleaseSemaphore(configsemaphore);
sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
sendExtCmd_nr(data,combuf,cpp);
return(FALSE);
}
/*= event_path() =====================================================================-.
`-====================================================================================*/
BOOL event_path(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
{
BOOL stoploop = FALSE;
if (arg2[0])
{
stoploop = TRUE;
listerRead(data,combuf,cpp,arg2);
}
else
{
sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
sendExtCmd_nr(data,combuf,cpp);
rereadConfig(data,combuf,cpp);
sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
sendExtCmd_nr(data,combuf,cpp);
}
return(stoploop);
}
/*= event_scandir_hotlist() ==========================================================-.
`-====================================================================================*/
BOOL event_scandir_hotlist(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
{
sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
sendExtCmd_nr(data,combuf,cpp);
rereadConfig(data,combuf,cpp);
sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
sendExtCmd_nr(data,combuf,cpp);
return(FALSE);
}
/*= event_snapshot() =================================================================-.
`-====================================================================================*/
BOOL event_snapshot(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
{
int x,y,w,h;
sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
sendExtCmd_nr(data,combuf,cpp);
getWriteConfigSemaphore(data);
sprintf(combuf,"lister query %s position",data->lister);
cpp->flags = COMMANDF_RESULT;
cpp->command = combuf;
data->func_callback(EXTCMD_SEND_COMMAND,IPCDATA(data->ipc),cpp);
// Backup the old values in case of failure.
x = data->snap.x;
y = data->snap.y;
w = data->snap.w;
h = data->snap.h;
if (4 == sscanf(cpp->result,"%d/%d/%d/%d",&(data->snap.x),\
&(data->snap.y),&(data->snap.w),&(data->snap.h)))
{
// Write new config (No point in re-reading it).
writeConfigFile(data);
}
else
{
// Failure: Restore the old values.
data->snap.x = x;
data->snap.y = y;
data->snap.w = w;
data->snap.h = h;
}
FreeVec(cpp->result);
cpp->result = NULL;
ReleaseSemaphore(configsemaphore);
sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
sendExtCmd_nr(data,combuf,cpp);
return(FALSE);
}
/*= event_unsnapshot() ===============================================================-.
`-====================================================================================*/
BOOL event_unsnapshot(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
{
sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
sendExtCmd_nr(data,combuf,cpp);
getWriteConfigSemaphore(data);
data->snap.x = data->snap.y = data->snap.w = data->snap.h = (-1);
writeConfigFile(data); // No point re-reading the config.
ReleaseSemaphore(configsemaphore);
sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
sendExtCmd_nr(data,combuf,cpp);
return(FALSE);
}
/*= event_rename() ===================================================================-.
`-====================================================================================*/
BOOL event_rename(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
{
BOOL needsave = FALSE;
BOOL gsr, fher;
HotEntry *ohe;
HotEntry *nhe;
ResNode *orn;
sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
sendExtCmd_nr(data,combuf,cpp);
getWriteConfigSemaphore(data);
if (orn = allocNewResNode(&data->rnd,HOTENTNAMELEN))
{
// Point past the initial quote.
if (*arg2 == '"') arg2++;
while(*arg2) // Do all words in the list (multi-drop).
{
wordcpy(orn->rn_Mem,&arg2);
if (ohe = findHotEntry(data,orn->rn_Mem))
{
if (nhe = newHotEntry(data))
{
strcpy(nhe->path,ohe->path);
strcpy(nhe->name,ohe->name);
// Mark the old entry as deleted so it won't show up in searches.
// Will be left deleted unless they cancel the new entry.
(ohe->deleted) = TRUE;
if ((getPathString(data,dgs(MSG_PATHFORRENAME_FMT),TRUE,0,
nhe->path,HOTENTPATHLEN,nhe->name)) && (nhe->path[0]))
{
do
{
gsr=getString(data,dgs(MSG_NAMEFORRENAME_FMT),TRUE,0,
nhe->name,HOTENTNAMELEN,nhe->path);
if ( (gsr) && (fher=findOldEntry(data,nhe->name)) )
{
informUser(data,dgs(MSG_NAMEDUPLIC_FMT),TRUE,0,
nhe->name);
}
} while( (gsr) && (fher) );
if ( (gsr) && (nhe->name[0]) )
{
setHotType(data,nhe); // Set the type of entry.
needsave = TRUE;
}
else
{
// Else abort adding this entry.
remHotEntry(data);
(ohe->deleted) = FALSE; // Undelete old entry.
break; // Don't do any more entries.
}
}
else
{
// Else abort adding this entry.
remHotEntry(data);
(ohe->deleted) = FALSE; // Undelete old entry.
break; // Don't do any more entries either.
}
}
}
}
if (needsave)
{
writeConfigFile(data);
rereadConfig(data,combuf,cpp);
}
deleteResNode(&data->rnd,orn);
}
ReleaseSemaphore(configsemaphore);
sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
sendExtCmd_nr(data,combuf,cpp);
return(FALSE);
}
/*= event_parent() ===================================================================-.
`-====================================================================================*/
BOOL event_parent(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
{
BOOL stoploop = FALSE;
ConfigListNode *clnp;
if (data->conflist) // 'Parent' hotlist-file, if there is one.
{
if (strstr(arg6,"shift"))
{
// If shift helf down, open a new hotlist for it.
sprintf(combuf,"command hotlist NEW CONFIG \"%s\"",\
((data->conflist->parent) ? (data->conflist->parent->rn->rn_Mem) :\
(data->originalconfig)) );
sendExtCmd_nr(data,combuf,cpp);
}
else
{
// If shift not held down, read it into the current lister.
// Get pointer to 'parent' config file's ConfigListNode.
clnp = (data->conflist->parent);
// Turn notify off before the filename mem is deallocated and made invalid.
notifyOff(data);
// Free the old, unwanted filename memory.
deleteResNode(&data->rnd,data->conflist->rn);
// Free the old, unwanted ConfigListNode.
deleteResNode(&data->rnd,data->conflist->rn_self);
// Make the parent of the 'old' node the top-level node.
(data->conflist) = clnp;
// Setup the filenames.
if (data->conflist)
{
// If there is still a parent config-file to go to, use it.
(data->config) = (data->conflist->rn->rn_Mem);
(data->notify.nr_Name) = (data->config);
}
else
{
// If there's no parent config-file, use the original one.
(data->config) = (data->originalconfig);
}
// Update the title.
sprintf(combuf,"lister set %s header (%s)",data->lister,data->config);
sendExtCmd_nr(data,combuf,cpp);
// Read in the 'new' config file.
rereadConfig(data,combuf,cpp);
}
}
else if (data->parent[0]) // Or 'real' parent dir, if there is one.
{
if (strstr(arg6,"shift"))
{
sprintf(combuf,"lister new %s",data->parent);
sendExtCmd_nr(data,combuf,cpp);
}
else
{
stoploop = TRUE;
listerRead(data,combuf,cpp,data->parent);
}
}
else // Otherwise just beep.
DisplayBeep(NULL);
return(stoploop);
}
/*= event_duplicate() ================================================================-.
`-====================================================================================*/
BOOL event_duplicate(Hotlist_Data *data,char *combuf,struct command_packet *cpp,\
char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
{
BOOL needsave = FALSE;
BOOL gsr, fher;
HotEntry *ohe;
HotEntry *nhe;
ResNode *orn;
sprintf(combuf,"lister set %s busy %s wait",data->lister,"on");
sendExtCmd_nr(data,combuf,cpp);
getWriteConfigSemaphore(data);
if (orn = allocNewResNode(&data->rnd,HOTENTNAMELEN))
{
// Point past the initial quote.
if (*arg2 == '"') arg2++;
while(*arg2) // Do all words in the list (multi-drop).
{
wordcpy(orn->rn_Mem,&arg2);
if (ohe = findHotEntry(data,orn->rn_Mem))
{
if (nhe = newHotEntry(data))
{
strcpy(nhe->path,ohe->path);
strcpy(nhe->name,ohe->name);
if ((getPathString(data,dgs(MSG_PATHFORNEW),TRUE,0,
nhe->path,HOTENTPATHLEN)) && (nhe->path[0]))
{
do
{
gsr=getString(data,dgs(MSG_NAMEFORPATH_FMT),TRUE,0,
nhe->name,HOTENTNAMELEN,nhe->path);
if ( (gsr) && (fher=findOldEntry(data,nhe->name)) )
{
informUser(data,dgs(MSG_NAMEDUPLIC_FMT),TRUE,0,
nhe->name);
}
} while( (gsr) && (fher) );
if ( (gsr) && (nhe->name[0]) )
{
setHotType(data,nhe); // Set the type of entry.
needsave = TRUE;
}
else
{
// Else abort adding this entry.
remHotEntry(data);
break; // Don't do any more entries.
}
}
else
{
// Else abort adding this entry.
remHotEntry(data);
break; // Don't do any more entries either.
}
}
}
}
if (needsave)
{
writeConfigFile(data);
rereadConfig(data,combuf,cpp);
}
deleteResNode(&data->rnd,orn);
}
ReleaseSemaphore(configsemaphore);
sprintf(combuf,"lister set %s busy %s wait",data->lister,"off");
sendExtCmd_nr(data,combuf,cpp);
return(FALSE);
}
/*= getConfigSemaphore() =============================================================-.
|| Get a lock on the configfile semaphore, showing a progress window if it isn't ||
|| immediately obtainable. obtype should be GCS_SHARED or GCS_EXCLUSIVE. ||
|| The semaphore returned should be freed with ReleaseSemaphore as usual. ||
`-====================================================================================*/
void getConfigSemaphore(Hotlist_Data *data,short obtype)
{
APTR progwin;
struct Window *win;
struct Screen *screen;
LONG goddit;
if (win = getListerWindow(data))
screen = NULL;
else
screen = getDOpusScreen(data);
if (obtype == GCS_SHARED)
goddit = AttemptSemaphoreShared(configsemaphore);
else
goddit = AttemptSemaphore(configsemaphore);
if ( !(goddit) )
{
progwin = OpenProgressWindowTags(
TAGIF(win,PW_Window), win,
TAGIF((!win) && screen,PW_Screen), screen,
PW_Title, dgs(MSG_TITLE),
PW_FileName, dgs(MSG_SEMWAIT),
PW_Flags, PWF_FILENAME,
TAG_END);
if (obtype == GCS_SHARED)
ObtainSemaphoreShared(configsemaphore);
else
ObtainSemaphore(configsemaphore);
if (progwin)
CloseProgressWindow(progwin);
}
}
/*= getWriteConfigSemaphore() ========================================================-.
|| This routine first gets exclusive access to the config file semaphore and then ||
|| re-reads the config file if file notification reports that it has changed. ||
|| You should call this routine to get your semaphore lock prior to changing any ||
|| config file data and writting a new config file. ||
|| I repeat: PRIOR TO CHANGING ANY CONFIG FILE DATA -- Don't just call it right ||
|| before calling writeConfigFile() as if the config file has changed it'll be ||
|| re-read, replacing any changes you have just made, and then written out again ||
|| exactly the same. ||
|| You should release the semaphore lock after you're finished writting with a call ||
|| to ReleaseSemaphore() -- writeConfigFile() won't do this for you! ||
||------------------------------------------------------------------------------------||
|| Currently it doesn't re-read the changed file as the notification routines are yet ||
|| to be written. I haven't even decided exactly how they will work. ||
`-====================================================================================*/
void getWriteConfigSemaphore(Hotlist_Data *data)
{
// First, get us exclusive access to the config file.
getConfigSemaphore(data,GCS_EXCLUSIVE);
// Now, if the file has changed, re-read.
if ((SetSignal(0,0)) & (data->notsigmask))
{
SetSignal(0,data->notsigmask);
// readConfigFile() won't get it's own semaphore lock as 2nd argument TRUE.
readConfigFile(data,TRUE);
}
}
/*= notifyOn() =======================================================================-.
|| Routine to handle turning on notification on the config file. Will set ||
|| data->notifyon to TRUE if it succeeds. Will not start another notification ||
|| request if data->notifyon indicates we already have one. As some filesystems do ||
|| not support notification, notification may still be off after this call. ||
|| The signal bit used for notification will be cleared. ||
`-====================================================================================*/
void notifyOn(Hotlist_Data *data)
{
// Unless notification already on, attempt to turn it on.
if (!(data->notifyon))
{
// If the signal is set, clear it.
// We could just clear it, but the autodocs/RKRM discourage it.
if ((SetSignal(0,0)) & (data->notsigmask))
SetSignal(0,data->notsigmask);
(data->notifyon) = StartNotify(&data->notify);
}
}
/*= notifyOff() ======================================================================-.
|| If data->notifyon indicates we have a notification request this routine will turn ||
|| it off and set data->notifyon to FALSE. ||
`-====================================================================================*/
void notifyOff(Hotlist_Data *data)
{
if (data->notifyon)
{
EndNotify(&data->notify);
(data->notifyon) = FALSE;
}
}
/*= SkipSpaces() =====================================================================-.
|| Returns pointer to just after the nth space in the string. ||
|| Returns pointer to the NULL at the end of the string if not enough spaces. ||
`-====================================================================================*/
char *skipSpaces(char *text,int numspac)
{
if (text)
{
while (*text && numspac)
{
if (*(text++) == ' ')
numspac--;
}
}
return text;
}